package com.gxa.community.admin.service.order.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gxa.community.admin.mapper.agent.UserAgentApplicationMapper;
import com.gxa.community.admin.mapper.goods.GoodsInfoMapper;
import com.gxa.community.admin.mapper.order.*;
import com.gxa.community.admin.service.order.WayBillService;
import com.gxa.community.core.pojo.bo.order.WayBillAndOrderNo;
import com.gxa.community.core.pojo.domain.*;
import com.gxa.community.core.pojo.vo.order.OrderInfoVo;
import com.gxa.community.core.pojo.vo.order.UserInfoVo;
import com.gxa.community.core.pojo.vo.order.WayBillInfoVo;
import com.gxa.community.core.pojo.vo.order.WayBillVo;
import com.gxa.community.core.utils.LittleUtils;
import com.gxa.community.core.utils.R;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class WayBillServiceImpl implements WayBillService {
    final OrderInfoMapper orderInfoMapper;
    final WayBillMapper wayBillMapper;
    final OrderGoodsInfoMapper orderGoodsInfoMapper;
    final OrderGoodsRelMapper orderGoodsRelMapper;
    final GoodsInfoMapper goodsInfoMapper;
    final UserInfoMapper userInfoMapper;
    final UserAgentApplicationMapper agentInfoMapper;
    final DriverInfoMapper driverInfoMapper;

    public WayBillServiceImpl(OrderInfoMapper orderInfoMapper, WayBillMapper wayBillMapper
            , OrderGoodsInfoMapper orderGoodsInfoMapper, OrderGoodsRelMapper orderGoodsRelMapper
            , GoodsInfoMapper goodsInfoMapper, UserInfoMapper userInfoMapper
            , UserAgentApplicationMapper userAgentApplicationMapper
            , DriverInfoMapper driverInfoMapper) {
        this.orderInfoMapper = orderInfoMapper;
        this.wayBillMapper = wayBillMapper;
        this.orderGoodsInfoMapper = orderGoodsInfoMapper;
        this.orderGoodsRelMapper = orderGoodsRelMapper;
        this.goodsInfoMapper = goodsInfoMapper;
        this.userInfoMapper = userInfoMapper;
        this.agentInfoMapper = userAgentApplicationMapper;
        this.driverInfoMapper = driverInfoMapper;
    }

    /**
     * 创建订单
     */
    @Override
    public R createWaybill(WayBillAndOrderNo wayBillAndOrderNo) {
        WaybillInfo waybillInfo = wayBillAndOrderNo.getWaybill();
        long timestamp = System.currentTimeMillis();

        // 生成运单号
        waybillInfo.setNo(LittleUtils.generateNo(16, timestamp))
                .setCreateTime(timestamp);

        // 创建运单
        if (wayBillMapper.insert(waybillInfo) > 0) {
            // 修改订单的运单号
            return editWayBillNo(wayBillAndOrderNo, waybillInfo);
        }
        return R.error("运单创建失败");
    }

    /**
     * 修改运单信息
     */
    @Override
    public R editWaybill(WayBillAndOrderNo wayBillAndOrderNo) {
        WaybillInfo waybillInfo = wayBillAndOrderNo.getWaybill();

        // 清空该运单之前的订单
        orderInfoMapper.update(new OrderInfo().setWaybillNo("0")
                , Wrappers.lambdaUpdate(OrderInfo.class).eq(OrderInfo::getWaybillNo, waybillInfo.getNo()));

        if (wayBillMapper.update(waybillInfo
                , Wrappers.lambdaQuery(WaybillInfo.class).eq(WaybillInfo::getNo, waybillInfo.getNo())) > 0) {
            // 修改订单的运单号
            return editWayBillNo(wayBillAndOrderNo, waybillInfo);
        }
        return R.error("运单信息修改失败");
    }

    /**
     * 确认发货
     */
    @Override
    public R confirmShipment(List<String> waybills) {
        if (wayBillMapper.update(new WaybillInfo().setStatus(2).setShipTime(System.currentTimeMillis())
                , Wrappers.lambdaUpdate(WaybillInfo.class).in(WaybillInfo::getNo, waybills)) > 0)
            return R.ok();
        return R.error("发货失败");
    }

    /**
     * 查询运单信息
     */
    @Override
    public R queryWaybill(Integer page, Integer size, WayBillVo wayBillVo) {
        /*
        agentId 所属团长ID
        agentPoint 团长所属区域   -> 团长id

        nick 下单人姓名 -> 下单人id

        receiver 收货人姓名

        联合在订单中查询运单id
        */

        Set<Object> agentIds = new HashSet<>();
        // 查询团长ID - 用于查询订单
        if (wayBillVo.getAgentId() != null || StringUtils.isNotBlank(wayBillVo.getAgentPoint()))
            agentIds = new HashSet<>(agentInfoMapper.selectObjs(Wrappers.lambdaQuery(UserAgentApplication.class)
                    .select(UserAgentApplication::getUserId)
                    .eq(wayBillVo.getAgentId() != null, UserAgentApplication::getUserId, wayBillVo.getAgentId())
                    .eq(StringUtils.isNotBlank(wayBillVo.getAgentPoint()), UserAgentApplication::getIslandAddress, wayBillVo.getAgentPoint())));

        Set<Object> buyerIds = new HashSet<>();
        // 查询下单人ID - 用于查询订单
        if (StringUtils.isNotBlank(wayBillVo.getNick()))
            buyerIds = new HashSet<>(userInfoMapper.selectObjs(Wrappers.lambdaQuery(UserInfo.class)
                    .select(UserInfo::getUserId)
                    .like(UserInfo::getNickName, wayBillVo.getNick())));

        Set<Object> wayBillIds = new HashSet<>();
        // 查询订单中的运单ID - 用于查询订单
        if (StringUtils.isNotBlank(wayBillVo.getOrderId())
                || StringUtils.isNotBlank(wayBillVo.getReceiver())
                || !agentIds.isEmpty()
                || !buyerIds.isEmpty()
        ) wayBillIds = new HashSet<>(orderInfoMapper.selectObjs(Wrappers.lambdaQuery(OrderInfo.class)
                .select(OrderInfo::getWaybillNo)
                .eq(StringUtils.isNotBlank(wayBillVo.getOrderId()), OrderInfo::getNos, wayBillVo.getOrderId())
                .in(!agentIds.isEmpty(), OrderInfo::getAgentId, agentIds)
                .in(!buyerIds.isEmpty(), OrderInfo::getBuyerId, buyerIds)
                .eq(StringUtils.isNotBlank(wayBillVo.getReceiver()), OrderInfo::getReceiverName, wayBillVo.getReceiver())));

        Page<WaybillInfo> waybillInfoPage = new Page<>(page, size);

        // 查询运单信息
        Page<WaybillInfo> infoPage = new LambdaQueryChainWrapper<>(wayBillMapper)
                .eq(StringUtils.isNotBlank(wayBillVo.getNo()), WaybillInfo::getNo, wayBillVo.getNo())
                .eq(wayBillVo.getStatus() != null, WaybillInfo::getStatus, wayBillVo.getStatus())
                .eq(StringUtils.isNotBlank(wayBillVo.getDriverId()), WaybillInfo::getDriverId, wayBillVo.getDriverId())
                .between(wayBillVo.getStartTime() != null || wayBillVo.getEndTime() != null
                        , WaybillInfo::getShipTime, wayBillVo.getStartTime(), wayBillVo.getEndTime())
                .eq(!wayBillIds.isEmpty(), WaybillInfo::getNo, wayBillIds)
                .page(waybillInfoPage);

        // 运单基础信息
        List<WaybillInfo> waybillInfos = infoPage.getRecords();

        if (waybillInfos == null || waybillInfos.isEmpty())
            return R.page(infoPage.getCurrent(), infoPage.getSize(), infoPage.getTotal(), new ArrayList<>());

        // -=-=-=-=-=-=-=-=-=-=-=-=-开始查询待返回信息子对象-=-=-=-=-=-=-=-=-=-=-=-=-

        // 司机信息
        HashMap<Object, DriverInfo> driverInfos = driverInfoMapper.selectList(
                Wrappers.lambdaQuery(DriverInfo.class)
                        .in(DriverInfo::getId, // 根据司机id列表查询
                                waybillInfos.stream()
                                        .map(WaybillInfo::getDriverId)
                                        .collect(Collectors.toSet()) // 获取司机ID列表
                        )
        ).stream().collect(HashMap::new, (map, driver) -> map.put(driver.getId(), driver), HashMap::putAll); // 将查询结果转为Map

        // 订单信息 (先不用循环试试) 运单编号:订单列表
        HashMap<String, List<OrderInfoVo>> orderInfos = orderInfoMapper.selectList(
                Wrappers.lambdaQuery(OrderInfo.class)
                        .in(OrderInfo::getWaybillNo,
                                waybillInfos.stream()
                                        .map(WaybillInfo::getNo)
                                        .collect(Collectors.toSet()) // 获取运单号列表
                        )
        ).stream().collect(HashMap::new, (map, order) -> {
            // 判断运单对应的订单列表是否存在
            if (map.containsKey(order.getWaybillNo()))
                map.get(order.getWaybillNo()).add(orderInfoToVo(order));
            else {
                // 装配
                List<OrderInfoVo> infos = new ArrayList<>();
                infos.add(orderInfoToVo(order));
                map.put(order.getWaybillNo(), infos);
            }
        }, HashMap::putAll);

        // 下单人/团长ID集合 (避免重复查询)
        Set<Integer> userIds = new HashSet<>();
        for (List<OrderInfoVo> value : orderInfos.values()) {
            userIds.addAll(value.stream().map(OrderInfoVo::getBuyerId).collect(Collectors.toSet()));
            userIds.addAll(value.stream().map(OrderInfoVo::getAgentId).collect(Collectors.toSet()));
        }

        // 查询用户信息
        HashMap<Integer, UserInfoVo> userInfos = userInfoMapper.selectList(
                Wrappers.lambdaQuery(UserInfo.class)
                        .in(!userIds.isEmpty(), UserInfo::getUserId, userIds)
        ).stream().collect(HashMap::new, (map, user) -> map.put(user.getUserId(), userToVo(user)), HashMap::putAll);


        // -=-=-=-=-=-=-=-=-=-=-=-=-开始装配待返回信息子对象-=-=-=-=-=-=-=-=-=-=-=-=-

        // 将团长信息与下单用户信息装配至订单
        for (List<OrderInfoVo> value : orderInfos.values())
            for (OrderInfoVo infoVo : value)
                infoVo.setUserInfo(userInfos.get(infoVo.getBuyerId()))
                        .setAgentInfo(userInfos.get(infoVo.getAgentId()));

        // 将订单信息装配至运单
        List<WayBillInfoVo> wayBillInfoVos = new ArrayList<>();
        for (WaybillInfo waybillInfo : waybillInfos) {
            wayBillInfoVos.add(new WayBillInfoVo()
                    .setNo(waybillInfo.getNo())
                    .setCreateTime(waybillInfo.getCreateTime())
                    .setDriver(driverInfos.get(waybillInfo.getDriverId()))
                    .setTips(waybillInfo.getTips())
                    .setStatus(waybillInfo.getStatus())
                    .setOrders(orderInfos.get(waybillInfo.getNo()))
            );
        }

        return R.page(infoPage.getCurrent(), infoPage.getSize(), infoPage.getTotal(), wayBillInfoVos);
    }

    /**
     * 修改订单的运单号
     */
    private R editWayBillNo(WayBillAndOrderNo wayBillAndOrderNo, WaybillInfo waybillInfo) {
        int update = orderInfoMapper.update(new OrderInfo().setWaybillNo(waybillInfo.getNo())
                , Wrappers.lambdaUpdate(OrderInfo.class)
                        .in(OrderInfo::getNos, wayBillAndOrderNo.getOrders())
                        .isNull(OrderInfo::getWaybillNo).or()
                        .in(OrderInfo::getWaybillNo, "0")
        );
        if (update > 0) return R.ok();
        return R.error("运单中的订单添加失败");
    }

    private OrderInfoVo orderInfoToVo(OrderInfo orderInfo) {
        return new OrderInfoVo()
                .setNo(orderInfo.getNos())
                .setCreateTime(orderInfo.getCreateTime())
                .setAgentId(orderInfo.getAgentId())
                .setBuyerId(orderInfo.getBuyerId())
                .setReceiverName(orderInfo.getReceiverName())
                .setReceiverPhone(orderInfo.getReceiverPhone())
                .setCouponId(orderInfo.getCouponId())
                .setPrice(orderInfo.getPrice().doubleValue())
                .setPayment(orderInfo.getPayment().doubleValue())
                .setType(orderInfo.getType())
                .setWaybillNo(orderInfo.getWaybillNo())
                .setStatus(orderInfo.getStatus());
    }

    private UserInfoVo userToVo(UserInfo userInfo) {
        return new UserInfoVo()
                .setUserId(userInfo.getUserId())
                .setNickName(userInfo.getNickName())
                .setCreateTime(userInfo.getCreateTime())
                .setPhone(userInfo.getPhone())
                .setAddress(userInfo.getAddress());
    }
}
